<template>
  <div id="cesiumContainer">
    <span class="longSum">{{ longSum + 'km' }}</span>
    <div class="operator">
      <span @click="operator('line')">测距</span>
      <span @click="operator('angle')">测角</span>
      <span @click="operator('point')">画点</span>
      <span @click="operator('model')">三维模型</span>
      <span @click="operator('modelMore')">批量加载三维模型</span>
      <span @click="operator('editModelMore')">批量移动三维模型</span>
      <span @click="operator('radarJamming')">雷达干扰</span>
      <span @click="operator('addMorePrimitivesText')">批量添加标牌</span>
      <span @click="operator('addPrimitivesTextMouse')">鼠标添加标牌</span>

    </div>
  </div>
</template>
<script setup lang="ts">
import * as Cesium from 'cesium'

if (!window.Cesium) {
  window.Cesium = Cesium
}
import {onMounted, ref} from 'vue'
import {createRectanglePoint} from "./methods/Marking/point";
import {createModelPrimitive, editModelPrimitive} from "./methods/createModel";
import {batchUpdatePositions, createModelMore} from "./methods/createModelMore";
import {updateJammingGeometry} from "./methods/radarJamming";
import {HighPerformanceBillboardManager} from "./methods/createPrimitivesText";

const positionsArr = ref<Array<object>>([])

const initCesium = () => {
  Cesium.Ion.defaultAccessToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIwNWY1NDhkNy00NDI4LTQyZWQtYTRmNS1iNGQ0MjMxNDIzZWMiLCJpZCI6MTU0NDA1LCJpYXQiOjE2ODk1NzY0ODl9.1zt09SfJKVhZNs-zzn3fN5pzpkrYEzatuDTZYviZx1I";
  window.viewer = new Cesium.Viewer('cesiumContainer', {
    // baseLayerPicker: false, // 如果设置为false，将不会创建右上角图层按钮。
    // geocoder: false, // 如果设置为false，将不会创建右上角查询(放大镜)按钮。
    // navigationHelpButton: false, // 如果设置为false，则不会创建右上角帮助(问号)按钮。
    // homeButton: false, // 如果设置为false，将不会创建右上角主页(房子)按钮。
    // sceneModePicker: false, // 如果设置为false，将不会创建右上角投影方式控件(显示二三维切换按钮)。
    // animation: false, // 如果设置为false，将不会创建左下角动画小部件。
    // timeline: false, // 如果设置为false，则不会创建正下方时间轴小部件。
    // fullscreenButton: false, // 如果设置为false，将不会创建右下角全屏按钮。
    // scene3DOnly: false, // 为 true 时，每个几何实例将仅以3D渲染以节省GPU内存。
    // shouldAnimate: true, // 默认true ，否则为 false 。此选项优先于设置 Viewer＃clockViewModel 。
    // // ps. Viewer＃clockViewModel 是用于控制当前时间的时钟视图模型。我们这里用不到时钟，就把shouldAnimate设为false
    // infoBox: false, // 是否显示点击要素之后显示的信息
    // sceneMode: 3, // 初始场景模式 1 2D模式 2 2D循环模式 3 3D模式  this.Cesium.SceneMode
    // requestRenderMode: false, // 启用请求渲染模式，不需要渲染，节约资源吧
    // // 地图影像这里选择的是天地图
    // imageryProvider: new Cesium.UrlTemplateImageryProvider({
    //   url: `https://t4.tianditu.gov.cn/img_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=img&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILECOL={x}&TILEROW={y}&TILEMATRIX={z}&tk=${TDTTK}`,
    //   maximumLevel: 18,
    // }),
    // selectionIndicator: false, // 关闭绿色选择框
    geocoder: false,   // 位置查找工具
    baseLayerPicker: false,// 图层选择器（地形影像服务）
    timeline: false, // 底部时间线
    homeButton: false,// 视角返回初始位置
    fullscreenButton: false, // 全屏
    animation: false,   // 左下角仪表盘（动画器件）
    sceneModePicker: false,// 选择视角的模式（球体、平铺、斜视平铺）
    navigationHelpButton: false, //导航帮助按钮
  })
  console.log('window.viewer', window.viewer)
  window.viewer.scene.globe.depthTestAgainstTerrain = true

  // window.viewer.scene.globe.enableLighting = true;
//   let data = [];
//   data[0] = [{longitude:116.405419, dimension:39.918034, height:0, time:0},{longitude:116.2821, dimension:39.918145, height:0, time:40},{longitude:115.497402, dimension:39.344641, height:70000, time:100},{longitude:107.942392, dimension:29.559967, height:70000, time:280}, {longitude:106.549265, dimension:29.559967, height:0, time:360}];
//   data[1] = [{longitude:116.405419, dimension:39.918034, height:0, time:0},{longitude:117.034586, dimension:39.881202, height:0, time:40},{longitude:116.340088, dimension:38.842224, height:70000, time:100},{longitude:113.489176, dimension:23.464017, height:70000, time:280}, {longitude:113.262084, dimension:23.13901, height:0, time:360}];
//   data[2] = [{longitude:118.838979, dimension:32.073514, height:0, time:0},{longitude:118.438838, dimension:32.03777, height:0, time:40},{longitude:117.802406, dimension:31.91231, height:70000, time:100},{longitude:104.043645, dimension:35.993845, height:70000, time:280}, {longitude:101.807224, dimension:36.660972, height:0, time:360}];
// // 起始时间
//   let start = Cesium.JulianDate.fromDate(new Date(2017,7,11));
// // 结束时间
//   let stop = Cesium.JulianDate.addSeconds(start, 360, new Cesium.JulianDate());
//
// // 设置始时钟始时间
//   window.viewer.clock.startTime = start.clone();
// // 设置时钟当前时间
//   window.viewer.clock.currentTime = start.clone();
// // 设置始终停止时间
//   window.viewer.clock.stopTime  = stop.clone();
// // 时间速率，数字越大时间过的越快
//   window.viewer.clock.multiplier = 10;
// // 时间轴
//   window.viewer.timeline.zoomTo(start,stop);
// // 循环执行,即为2，到达终止时间，重新从起点时间开始
//   window.viewer.clock.clockRange = Cesium.ClockRange.LOOP_STOP;
//
// // window.viewer.camera.flyTo({
// //     destination:Cesium.Cartesian3.fromDegrees(116.405419,32.073514,20000)
// // })
//   for(let j=0; j<data.length; j++){
//     let property = computeFlight(data[j]);
//     //console.log(property)
//     // 添加模型
//     let planeModel = window.viewer.entities.add({
//       // 和时间轴关联
//       availability : new Cesium.TimeIntervalCollection([new Cesium.TimeInterval({
//         start : start,
//         stop : stop
//       })]),
//       position: property,
//       // 根据所提供的速度计算模型的朝向
//       orientation: new Cesium.VelocityOrientationProperty(property),
//       // 模型数据
//       model: {
//         uri: './Apps/SampleData/models/CesiumAir/Cesium_Air.glb',
//         minimumPixelSize:128
//       }
//     });
//
//   }


  /**
   * 计算飞行
   * @param source 数据坐标
   * @returns {SampledPositionProperty|*}
   */
  function computeFlight(source) {
    // 取样位置 相当于一个集合
    let property = new Cesium.SampledPositionProperty();
    for (let i = 0; i < source.length; i++) {
      let time = Cesium.JulianDate.addSeconds(start, source[i].time, new Cesium.JulianDate);
      let position = Cesium.Cartesian3.fromDegrees(source[i].longitude, source[i].dimension, source[i].height);
      // 添加位置，和时间对应
      property.addSample(time, position);
    }
    return property;
  }


  var handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas);
  handler.setInputAction(function (event) {
    // 鼠标右键取消画线动作
    endOperator()

  }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);


  getSpace()
  window.viewer.cesiumWidget.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK)

}

/**
 * @description 结束测距/测角操作
 */
const endOperator = () => {
  startOperator = () => {

  }
  // 根据entity（实体）对象删除
  // viewer.entities.removeAll()
  // positionsArr.value = []
  // longSum.value = 0
}

/**
 * @description 操作栏
 * @param val line 测距  angle 测角
 */
const operator = async (val) => {
  console.log('val', val)
  const billboardManager = new HighPerformanceBillboardManager(viewer);

  endOperator()
  switch (val) {
    case 'line':
      console.log('line')
      getLine();
      break
    case 'angle':
      getAngle();
      break
    case 'point':
      getPoint();
      break
    case 'model':
      let planeModel = {
        id: 'car-1',
        url: '/model/Cesium_Air.glb',
        position: {lon: -116.40, lat: 39.92, hei: 5000},
        scale: 2.0,
        height: 0,
        color: Cesium.Color.fromCssColorString('#ff0011')
      }
      for (let i = 0; i < 1000; i++) {
        let plane = JSON.parse(JSON.stringify((planeModel)))
        plane.id += i + ''
        plane.position.lat -= i / 100
        plane.text = String(i) + plane.position.lon + ',' + plane.position.lat + ',' + plane.position.hei
        createModelPrimitive(
            plane
        )
        setInterval(() => {
          plane.position.lon += 1 / 100
          plane.text = String(i) + plane.position.lon + ',' + plane.position.lat + ',' + plane.position.hei
          editModelPrimitive(plane)
        }, 0)
      }
      break
    case 'modelMore':
      createModelMore()
      break
    case 'editModelMore':
      setInterval(() => {
        batchUpdatePositions(0.001, 0.001, 0.5)
      }, 0)
      break
    case 'radarJamming':
      updateJammingGeometry()
      break
    case 'addMorePrimitivesText':

      // 初始化图标管理器
      const testData = generateTestData(10000);
      const result = await billboardManager.addBillboardsBatch(testData);
      console.log('result',result)
      break
    case 'addPrimitivesTextMouse':
      // 初始化图标管理器
      billboardManager.addIcon({
        name: '新地点',
        color: '#2196F3',
        iconText: '⭐'
      })
      break
    default :
      ''
  }
}

// 生成测试数据
function generateTestData(count) {
  const data = [];
  const colors = [
    '#FF5252', '#FF4081', '#E040FB', '#7C4DFF',
    '#536DFE', '#448AFF', '#40C4FF', '#18FFFF',
    '#64FFDA', '#69F0AE', '#B2FF59', '#EEFF41',
    '#FFFF00', '#FFD740', '#FFAB40', '#FF6E40'
  ];

  const icons = ['🏠', '🏢', '🏣', '🏤', '🏥', '🏦', '🏨', '🏩', '🏪', '🏫', '🏬', '🏭', '🏯', '🏰'];
  const locations = ['北京', '上海', '广州', '深圳', '杭州', '成都', '重庆', '武汉', '西安', '南京'];

  for (let i = 0; i < count; i++) {
    const locationIndex = i % locations.length;
    data.push({
      longitude: 116.39 + (Math.random() * 10 - 5),  // 北京周边±5度
      latitude: 39.91 + (Math.random() * 10 - 5),    // 北京周边±5度
      height: Math.random() * 5000,
      color: colors[i % colors.length],
      iconText: icons[i % icons.length],
      name: `${locations[locationIndex]} - 地点${i + 1}`
    });
  }
  return data;
}

/**
 * @description 获取经纬度
 */
const getSpace = () => {
  let handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
  handler.setInputAction(function (event) {
    let cartesian = viewer.camera.pickEllipsoid(event.position);
    let cartographic = Cesium.Cartographic.fromCartesian(cartesian);
    let lng = Cesium.Math.toDegrees(cartographic.longitude); // 经度
    let lat = Cesium.Math.toDegrees(cartographic.latitude); // 纬度
    let alt = cartographic.height; // 高度，椭球面height永远等于0
    let coordinate = {
      longitude: Number(lng.toFixed(6)),
      latitude: Number(lat.toFixed(6)),
      altitude: Number(alt.toFixed(2))
    };

    var position = viewer.scene.camera.pickEllipsoid(event.position, viewer.scene.globe.ellipsoid);
    startOperator(position, coordinate)
  }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
}

/**
 * @description 画线操作
 */

const getLine = () => {
  // 画线方法
  startOperator = (position, coordinate) => {
    // 画线方法
    createPolyline(position, coordinate)
  }
}

/**
 * @description 画线/测角
 * @param position
 * @param coordinate
 */
let startOperator = (position, coordinate) => {

}

/**
 * @description 测角操作
 */
const getAngle = () => {
  // 替换为测角
  startOperator = (position, coordinate) => {
    // 替换为测角
    createPolyAngle(position, coordinate)
  }
}

let num = 0
/**
 * @description 画点操作
 */
const getPoint = () => {
  // 替换为测角
  startOperator = (position, coordinate) => {
    // 替换为测角
    createRectanglePoint(position)
    const entity = viewer.entities.getById(0)//根据id获取到指定实体
    const entity2 = viewer.entities.getById(1)//根据id获取到指定实体
    window.viewer._selectedEntity = [entity, entity2];//选中实体
    // window.viewer._selectedEntity = entity2;//选中实体
  }
}


let longSum = ref<number>(0)

/**
 * @description 测距离
 * @param positions xyz
 * @param coordinate 经纬度
 */
const createPolyline = function (positions, coordinate) {
  createRectanglePoint(positions)
  positionsArr.value.push({
    positions,
    coordinate
  })
  if (positionsArr.value.length > 1) {
    window.viewer.entities.add({
      polyline: {
        // 鼠标移动绘制
        // positions: new Cesium.CallbackProperty(function () {
        //     return positions
        // }, false),
        positions: positionsArr.value.map(m => {
          return m.positions
        }),
        show: true,
        material: Cesium.Color.RED,
        depthFailMaterial: new Cesium.PolylineOutlineMaterialProperty({ // 折线低于地形时用于绘制折线的材料
          color: Cesium.Color.RED
        }),
        width: 2,
        clampToGround: true,
        eyeOffset: new Cesium.Cartesian3(0, 0, -100),
        heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
      }
    });
    console.log('positionsArr', positionsArr)
    if (positionsArr.value.length > 1) {
      let long = getDistance(positionsArr.value[positionsArr.value.length - 2].coordinate, positionsArr.value[positionsArr.value.length - 1].coordinate)

      longSum.value += long
      window.viewer.entities.add({
        position: positionsArr.value[positionsArr.value.length - 1].positions,
        point: {
          pixelSize: 10,
          color: Cesium.Color.YELLOW,
          eyeOffset: new Cesium.Cartesian3(0, 0, -300),
          heightReference: Cesium.HeightReference.CLAMP_TO_GROUND
        },
        label: {
          text: long + 'km',
          font: 'normal 24px SimHei',
          fillColor: Cesium.Color.WHITE, // 文本颜色
          backgroundColor: Cesium.Color.WHITE, // 背景色
          style: Cesium.LabelStyle.FILL, // 文本样式，轮廓
          outlineWidth: 2, // 轮廓宽度
          verticalOrigin: Cesium.VerticalOrigin.BOTTOM, // 圆点位置
          horizontalOrigin: Cesium.HorizontalOrigin.LEFT, // 文本的位置
          pixelOffset: new Cesium.Cartesian2(0, -10), // 文本偏移量，Cartesian2
        }
      })

    }
  }
}

/**
 * @description 测角度
 * @param positions xyz
 * @param coordinate 经纬度
 */
const createPolyAngle = function (positions, coordinate) {
  createRectanglePoint(positions)
  positionsArr.value.push({
    positions,
    coordinate
  })
  console.log('positionsArr', positionsArr.value.length)
  if (positionsArr.value.length > 1) {
    window.viewer.entities.add({
      polyline: {
        // 鼠标移动绘制
        // positions: new Cesium.CallbackProperty(function () {
        //     return positions
        // }, false),
        positions: positionsArr.value.map(m => {
          return m.positions
        }),
        show: true,
        material: Cesium.Color.RED,
        depthFailMaterial: new Cesium.PolylineOutlineMaterialProperty({ // 折线低于地形时用于绘制折线的材料
          color: Cesium.Color.RED
        }),
        width: 2,
        clampToGround: true,
        eyeOffset: new Cesium.Cartesian3(0, 0, -100),
        heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
      }
    });
    if (positionsArr.value.length > 1) {
      let long = getDistance(positionsArr.value[positionsArr.value.length - 2].coordinate, positionsArr.value[positionsArr.value.length - 1].coordinate)

      longSum.value += long
      window.viewer.entities.add({
        position: positionsArr.value[positionsArr.value.length - 1].positions,
        point: {
          pixelSize: 10,
          color: Cesium.Color.YELLOW,
          eyeOffset: new Cesium.Cartesian3(0, 0, -300),
          heightReference: Cesium.HeightReference.CLAMP_TO_GROUND
        },
        label: {
          text: long + 'km',
          font: 'normal 24px SimHei',
          fillColor: Cesium.Color.WHITE, // 文本颜色
          backgroundColor: Cesium.Color.WHITE, // 背景色
          style: Cesium.LabelStyle.FILL, // 文本样式，轮廓
          outlineWidth: 2, // 轮廓宽度
          verticalOrigin: Cesium.VerticalOrigin.BOTTOM, // 圆点位置
          horizontalOrigin: Cesium.HorizontalOrigin.LEFT, // 文本的位置
          pixelOffset: new Cesium.Cartesian2(0, -10), // 文本偏移量，Cartesian2
        }
      })

    }
  }
  // 结束
  if (positionsArr.value.length === 3) {
    console.log(123)
    startOperator = () => {

    }
  }
}

const getDistance = (position1, position2) => {
  let lat1 = position1.longitude // 经度
  let lng1 = position1.latitude // 纬度
  let lat2 = position2.longitude
  let lng2 = position2.latitude

  function Rad(d) {
    return d * Math.PI / 180.0;//经纬度转换成三角函数中度分表形式。
  }

  var radLat1 = Rad(lat1);
  var radLat2 = Rad(lat2);
  var a = radLat1 - radLat2;
  var b = Rad(lng1) - Rad(lng2);
  var s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) +
      Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2)));
  s = s * 6378.137;// EARTH_RADIUS;
  s = Math.round(s * 10000) / 10000; //输出为公里
//s=s.toFixed(4);
  return s || 0;
}

onMounted(() => {
  initCesium()
})
</script>
<script lang="ts">
export default {
  name: 'DbxGisEarth'
}
</script>
<style scoped lang="scss">
#cesiumContainer {
  height: 100vh;
  width: 100vw;
  overflow: hidden;
  position: relative;

  .longSum {
    position: absolute;
    top: 0;
    font-size: 30px;
    color: #fff;
    font-weight: 700;
    z-index: 1;
  }

  .operator {
    position: absolute;
    top: 100px;
    font-size: 16px;
    color: #fff;
    font-weight: 700;
    z-index: 1;
    display: flex;
    flex-wrap: wrap;
    width: 200px;

    span {
      cursor: pointer;
      display: inline-block;
      width: 100%;
      cursor: pointer;

    }

    span:hover {
      background: #66ccee;
    }
  }
}
</style>